//////////////////////////////////////////////////////////////////////////////
//																			//
//  Filename:    AchillesGuts.cpp											//
//  Developer:   Ben Wardlow												//
//  Create date: 5/15/2006													//
//																			//
//////////////////////////////////////////////////////////////////////////////
//																			//
//  Description: This is the class implementation for the slot gut of the	//
//               Australian Slot machine called Achilles.					//
//																			//
//////////////////////////////////////////////////////////////////////////////
//        Copyright (c) 2006 - Realtime Gaming.  All rights reserved.		//
//////////////////////////////////////////////////////////////////////////////

#include "AchillesGuts.h"
//#define DEBUG_KNOWNSPINS

////////////////////////////////////////////////////////////////////////////
/// AchillesGuts::m_aLineWinSpinResults
///
/// This array is used to quickly get the SpinResult for the number of
/// icons.  It is indexed by wheel icon and then count.  So to get the
/// SpinResult for 5 Horses, use the following code snippet:
///
///		SpinResult result = m_aLineWinSpinResults[ ICON_HORSE ][ 5 ];
///
/// In this example result would be set to EVT_FIVE_HORSE.
////////////////////////////////////////////////////////////////////////////
AchillesGuts::SpinResult AchillesGuts::m_aLineWinSpinResults[][6] =
{
// Number of icons:		0			1					2					3					4					5
/* ICON_NINE */		{	EVT_LOSER,	EVT_LOSER,			EVT_LOSER,			EVT_THREE_NINE,		EVT_FOUR_NINE,		EVT_FIVE_NINE		},
/* ICON_TEN */		{	EVT_LOSER,	EVT_LOSER,			EVT_LOSER,			EVT_THREE_TEN,		EVT_FOUR_TEN,		EVT_FIVE_TEN		},
/* ICON_JACK */		{	EVT_LOSER,	EVT_LOSER,			EVT_LOSER,			EVT_THREE_JACK,		EVT_FOUR_JACK,		EVT_FIVE_JACK		},
/* ICON_QUEEN */	{	EVT_LOSER,	EVT_LOSER,			EVT_LOSER,			EVT_THREE_QUEEN,	EVT_FOUR_QUEEN,		EVT_FIVE_QUEEN		},
/* ICON_KING */		{	EVT_LOSER,	EVT_LOSER,			EVT_LOSER,			EVT_THREE_KING,		EVT_FOUR_KING,		EVT_FIVE_KING		},
/* ICON_ACE */		{	EVT_LOSER,	EVT_LOSER,			EVT_LOSER,			EVT_THREE_ACE,		EVT_FOUR_ACE,		EVT_FIVE_ACE		},
/* ICON_HELM */		{	EVT_LOSER,	EVT_LOSER,			EVT_TWO_HELM,		EVT_THREE_HELM,		EVT_FOUR_HELM,		EVT_FIVE_HELM		},
/* ICON_SHIELD */	{	EVT_LOSER,	EVT_LOSER,			EVT_TWO_SHIELD,		EVT_THREE_SHIELD,	EVT_FOUR_SHIELD,	EVT_FIVE_SHIELD		},
/* ICON_HORSE */	{	EVT_LOSER,	EVT_LOSER,			EVT_TWO_HORSE,		EVT_THREE_HORSE,	EVT_FOUR_HORSE,		EVT_FIVE_HORSE		},
/* ICON_HELEN */	{	EVT_LOSER,	EVT_LOSER,			EVT_TWO_HELEN,		EVT_THREE_HELEN,	EVT_FOUR_HELEN,		EVT_FIVE_HELEN		},
/* ICON_TROY */		{	EVT_LOSER,	EVT_LOSER,			EVT_LOSER,			EVT_LOSER,			EVT_LOSER,			EVT_LOSER			},
/* ICON_ACHILLES */	{	EVT_LOSER,	EVT_ONE_ACHILLES,	EVT_TWO_ACHILLES,	EVT_THREE_ACHILLES,	EVT_FOUR_ACHILLES,	EVT_FIVE_ACHILLES	},
};


////////////////////////////////////////////////////////////////////////////
/// AchillesGuts::m_aScatterWinSpinResults
///
/// This array is used to quickly get the SpinResult for the number of
/// icons.  It is indexed by icon count only, since Troy is the only
/// scatter win.  So to get the SpinResult for 3 Troys, use the
/// following code snippet:
///
///		SpinResult result = m_aScatterWinSpinResults[ 3 ];
///
/// In this example result would be set to EVT_THREE_TROY.
////////////////////////////////////////////////////////////////////////////
AchillesGuts::SpinResult AchillesGuts::m_aScatterWinSpinResults[6] =
{
	// ICON_TROY		   Number of Icons
	EVT_LOSER,				// 0
	EVT_SCATTER_NEAR_MISS,	// 1 bwardlow 23-Jun-2006 #13252
	EVT_SCATTER_NEAR_MISS,	// 2
	EVT_THREE_TROY,			// 3
	EVT_FOUR_TROY,			// 4
	EVT_FIVE_TROY,			// 5
};


////////////////////////////////////////////////////////////////////////////
/// @fn 	 AchillesGuts::AchillesGuts()
///
/// This is the default constructor for the class.
////////////////////////////////////////////////////////////////////////////
AchillesGuts::AchillesGuts()
{
	// If this doesn't compile it means that someone probably added
	// another icon type but did not update the m_aLineWinSpinResults array.
	C_ASSERT( countof( m_aLineWinSpinResults ) == NUM_VALID_ICONS );
}


////////////////////////////////////////////////////////////////////////////
/// @fn 	 AchillesGuts::~AchillesGuts()
///
/// This is the destructor for the class.
////////////////////////////////////////////////////////////////////////////
AchillesGuts::~AchillesGuts()
{
}


////////////////////////////////////////////////////////////////////////////
/// @fn 	 AchillesGuts::SpinResult AchillesGuts::getAchillesLineWinResult( uint8* stops ) const
///
/// @param   stops			The array of stop positions for the line.
///
/// @return	 SpinResult		A payout from the SpinResult enumeration.
///
/// This helper method is used to calculate the Achilles line win payout.
////////////////////////////////////////////////////////////////////////////
AchillesGuts::SpinResult AchillesGuts::getAchillesLineWinResult( uint8* stops ) const
{
	// Count how many Achilles we have at the beginning of the line.
	for ( uint8 i = 0; i < getReelCount(); i++ )
    {
		// If this icon is not Achilles...
		if ( getIcon( getGameModeId(), i, stops[i] )->iconid != ICON_ACHILLES )
		{
			// then we have our total.
			break;
		}
    }

	// Use the array to look up the spin result for i Achilles icons.
	return lookupLineWinSpinResult( ICON_ACHILLES, i );
}


////////////////////////////////////////////////////////////////////////////
/// @fn 	 bool AchillesGuts::doesAchillesLineWinPayMore( SpinResult srAchilles, SpinResult srOther ) const
///
/// @param   srAchilles				The spin result to calculate the Achilles payout for.
/// @param   srOther				The spin result to calculate the other payout for.
///
/// @return	 bool					True if the Achilles win is larger.
///
/// This helper method is used to see which payout is larger.
////////////////////////////////////////////////////////////////////////////
bool AchillesGuts::doesAchillesLineWinPayMore( SpinResult srAchilles, SpinResult srOther ) const
{
	// If the Achilles line win is five Achilles, then no substitution took place
	// and we want to use the line win.
	if ( srAchilles == EVT_FIVE_ACHILLES )
	{
		return true;
	}

	// Lookup the payout for the Achilles line win.
	long nAchillesLineWinPayout = getPayout( srAchilles )->payoutAmount;

	// See what the total payout for the other line win is without the substitution
	// multiplier (if any).
	long nOtherLineWinPayout = getPayout( srOther )->payoutAmount;

	// Return true if the Achilles payout is bigger.
    return ( nAchillesLineWinPayout > nOtherLineWinPayout );
}


////////////////////////////////////////////////////////////////////////////
/// @fn 	 AchillesGuts::classifyStops()
///
/// @param   stops      The array of stop positions for the line.
/// @param   bet        The value of the line bet.
/// @param   line       The index of the line.
///
/// @return	 uint8      A payout from the SpinResult enumeration as a uint8.
///
/// This helper method is used to calculate the payout on a line.
////////////////////////////////////////////////////////////////////////////
void AchillesGuts::classifyStops( SpinLine* spinline, uint8* stops, uint8 bet,
	uint8 line, uint8& rtnresult, uint8& multiplier )
{
	// Track the Achilles result separately since it might be changed to a substitution.
	SpinResult srAchillesLineWinResult = getAchillesLineWinResult( stops );

	// Declare a local variable to track whether or not we found a substitution.
	bool bSubstitution = false;

	// Also keep track of the number of relevant icons for a line win
	uint8 nNumIcons = 0;

	// Now see what the payout is if we use any Achilles we find as substitution symbols.
	// Start with the icon on the first reel, since all symbols pay left to right.
	uint8 testIcon = getIcon( getGameModeId(), 0, stops[0] )->iconid;

	// See what the spin result is if we used any Achilles as substitution symbols.
	SpinResult srResultWithPossibleSubstitution =
		getLineWinResultWithPossibleSubstitution( stops, testIcon, bSubstitution, nNumIcons );

	// Use the larger payout between the regular Achilles evaluation compared to
	// the evaluation with the possible Achilles substitution.
    if ( doesAchillesLineWinPayMore( srAchillesLineWinResult, srResultWithPossibleSubstitution ) )
	{
		// The Achilles by themselves pay out more so use the Achilles result.
		rtnresult = srAchillesLineWinResult;
	}
	else
	{
		// Otherwise the result with the substitution (if any) paid more so use it.
		rtnresult = srResultWithPossibleSubstitution;

		// If we did actually have a substitution and a winning spin...
		if ( bSubstitution && srResultWithPossibleSubstitution != EVT_LOSER )
		{
			// then add a note.
			spinline->addNote( NOTE_ACHILLES_SUBSTITUTION );
		}
	}
}


////////////////////////////////////////////////////////////////////////////
/// @fn 	 AchillesGuts::SpinResult AchillesGuts::getLineWinResultWithPossibleSubstitution( uint8* stops, uint8 testIcon, bool& bSubstitution ) const
///
/// @param   stops			The array of stop positions for the line.
/// @param   testIcon		The icon we are looking for, typically the first icon on the line.
/// @param   bSubstitution	An output parameter that is set if a subsitution is used.
///
/// @return	 SpinResult		A payout from the SpinResult enumeration.
///
/// This helper method is used to calculate the line win payout with a possible substitution.
////////////////////////////////////////////////////////////////////////////
AchillesGuts::SpinResult AchillesGuts::getLineWinResultWithPossibleSubstitution(
	uint8* stops, uint8 testIcon, bool& bSubstitution, uint8& numLineWinIcons ) const
{
	// Initialize the out parameter
	bSubstitution = false;

	// Loop through the remaining reels until the streak is over
	for ( int i = 1; i < getReelCount(); i++ )
    {
		// See what this icon is.
		uint8 currentIcon = getIcon( getGameModeId(), i, stops[i] )->iconid;

		// If the current icon is Achilles...
		if ( currentIcon == ICON_ACHILLES )
		{
			// then use it as a substitution symbol and continue on.
			bSubstitution = true;
			continue;
		}
		// Otherwise if the test icon is Achilles...
		else if ( testIcon == ICON_ACHILLES )
		{
			// then we still have a substitution.  In this case the line
			// started out with Achilles.
			bSubstitution = true;

			// We have now found our first icon that is not Achilles.  All
			// of the rest of the icons will have to match this one now for the
			// streak to continue, so change our test icon.
			testIcon = currentIcon;
			continue;
		}

		// If the current icon is not the test icon...
        if ( currentIcon != testIcon )
        {
			// then the streak is over so break out of the loop
			break;
        }
    }

	// Pass this information back to the calling function so we can determine how many
	// Achilles icons, if any, contributed to the line win
	numLineWinIcons = i;

	// Use the array to look up the spin result for i testIcons.
	return lookupLineWinSpinResult( testIcon, i );
}


////////////////////////////////////////////////////////////////////////////
/// @fn 	 AchillesGuts::classifyScatters( SlotSpin* spin )
///
/// @param   spin       Pointer to the spin with stop data.
///
/// This is an override of the framework method.
/// It determines if the current spin merits free spins or scatter payments.
////////////////////////////////////////////////////////////////////////////
void AchillesGuts::classifyScatters( SlotSpin* spin )
{
	// Try for the Random Progressive Jackpot
	tryForJackpot( spin );

	// Declare a local variable to track the scatter positions.
	int32 nScatterPositions = 0;

	// See if there is a scatter.
	SpinResult srResult = getScatterWinResult( spin, nScatterPositions );

	// Add the scatter, if any.
	evaluateScatterWin( spin, srResult, nScatterPositions );

	// See if we triggered the free game feature.
	evaluateFeatureTrigger( spin, srResult, nScatterPositions );
}


////////////////////////////////////////////////////////////////////////////
/// @fn		AchillesGuts::getScatterWinResult( SlotSpin* spin, int32& scatterPositions )
///
/// @param   spin				The spin we are evaluating.
/// @param   scatterPositions	An output parameter that contains a bit mask for the icon positions.
///
/// @return	 SpinResult			A payout from the SpinResult enumeration.
///
///	This function looks for scatter wins.
////////////////////////////////////////////////////////////////////////////
AchillesGuts::SpinResult AchillesGuts::getScatterWinResult( SlotSpin* spin, int32& scatterPositions ) const
{
	// Declare a local variable to keep up with the icon count.
	uint8 numScatterIcons = 0;

	// Initialize the scatterPositions.
	scatterPositions = 0;

	// Loop through each reel.
  	for( int reel = 0; reel < getReelCount(); reel++ )
	{
		// The position bit for the current icon in case it needs to be stored in a mask.
		uint8 position = reel;

		// Loop through each row in the wheel house.
		for( int row = 0; row < 3; row++ )
		{
			// Get the current stop.
			uint8 stop = relativeWheelPosition( getGameModeId(), reel,
				spin->getStops()[ reel ], row );

			// Get the icon for the current stop.
			uint8 currentIcon = getIcon( getGameModeId(), reel, stop )->iconid;

			// If the icon is the one we are looking for...
			if ( currentIcon == ICON_TROY )
			{
				// then increase the icon count
				numScatterIcons++;

				// Set the bit in the position mask for this stop.
				scatterPositions |= 1 << position;
			}

			// Move to the next bit in the position mask.
            position += 5;
		}
	}

	return lookupScatterWinSpinResult( numScatterIcons );
}


////////////////////////////////////////////////////////////////////////////
/// @fn 	 AchillesGuts::evaluateScatterWin()
///
/// This function determines if the current spin wins a scatter payment and
/// adds the scatter.
////////////////////////////////////////////////////////////////////////////
void AchillesGuts::evaluateScatterWin( SlotSpin* spin, SpinResult srScatterResult, int32 scatterPositions )
{
	// If we got the scatter win (or almost got it)
	if ( srScatterResult != EVT_LOSER )
	{
		// Initialize the multiplier.
		int32 multiplier = 1;

		// If we are in the Troy feature mode...
		// Note that there are no Troy icons used during the Achilles feature, so we
		// don't have to worry about that here.
		if ( getGameModeId() == MODE_TROY_FREE_SPIN )
		{
			// then use the Troy free spin multiplier.
			multiplier = MULTIPLIER_TROY_FREE_SPIN;
		}

		// Get the base payout for the scatter.
		int32 nPayout = getPayout( srScatterResult )->payoutAmount;

		// Scatters payout based on the total bet, so factor in the number of bet lines.
		nPayout *= spin->getSpinLineCount();

		// Add the payout (with multiplier) to the total win for this spin.
		increaseTotalWin( nPayout * multiplier );

		// Add a scatter to the spin.
		SlotScatter* pScatter = spin->addScatter( scatterPositions,
			nPayout * getBetPerLine(), multiplier, false, srScatterResult, 0 );

		// If the free spin multiplier was used...
		if ( multiplier == MULTIPLIER_TROY_FREE_SPIN )
		{
			// then add the free spin note.
			pScatter->addNote( NOTE_TROY_FREE_SPIN );
		}
	}
}


////////////////////////////////////////////////////////////////////////////
/// @fn 	 AchillesGuts::setSelectAchillesIcon( int32 bSelectAchillesIcon )
///
/// @param   bSelectAchillesIcon  Flag indicating whether or not we are waiting
///								  for the player to select an icon.
///
/// This is a mutator to set if the game is requesting an Achille icon to be selected.
////////////////////////////////////////////////////////////////////////////
void AchillesGuts::setSelectAchillesIcon( int32 bSelectAchillesIcon )
{
    m_subGame->update( SGDIDX_FEATURE_SELECT_ACHILLES_ICON, bSelectAchillesIcon );
}


////////////////////////////////////////////////////////////////////////////
/// @fn 	 AchillesGuts::getSelectAchillesIcon() const
///
/// @return  int32   The 0-based reel selected.
///
/// This is an accessor mutator method to get if the game is requesting the Achilles icon selected.
////////////////////////////////////////////////////////////////////////////
int32 AchillesGuts::getSelectAchillesIcon() const
{
    return m_subGame->getData( SGDIDX_FEATURE_SELECT_ACHILLES_ICON );
}


////////////////////////////////////////////////////////////////////////////
/// @fn      AchillesGuts::setAchillesIconMask( int32 scatterPositions )
///
/// @param   scatterPositions	The bit mask for the scatter positions that we find.
///
/// Sets the mask of reels that have Achilles icons.
////////////////////////////////////////////////////////////////////////////
void AchillesGuts::setAchillesIconMask( int32 scatterPositions )
{
	m_subGame->update( SGDIDX_ACHILLES_MASK, scatterPositions );
}


////////////////////////////////////////////////////////////////////////////
/// @fn 	 AchillesGuts::evaluateFeatureTrigger( SlotSpin* spin, SpinResult srScatterResult, int32 featurePositions )
///
/// This function determines if the current spin triggers the free game
///	feature and adds the scatter.
////////////////////////////////////////////////////////////////////////////
void AchillesGuts::evaluateFeatureTrigger( SlotSpin* spin, SpinResult srScatterResult, int32 featurePositions )
{
	// We need a spin result for the feature trigger.
	SpinResult srFeatureTrigger = srScatterResult;

	// We need a place to keep up with how many free spins to award.
	int32 nFreeSpins = 0;

	// Keep up with how many of each icon we have...
	uint8 nNumAchilles = 0;
	uint8 nNumTroy = 0;

	// and where they are.
	int32 nAchillesScatter = 0;
	int32 nTroyScatter = 0;

	nNumAchilles = getNumFeatureTriggerIcons( spin, ICON_ACHILLES, nAchillesScatter );
	nNumTroy = getNumFeatureTriggerIcons( spin, ICON_TROY, nTroyScatter );

	// Assume that we did not trigger the Achilles feature.
	setSelectAchillesIcon( false );
	setAchillesIconMask( 0 );
	m_subGame->update( SGDIDX_FREE_SPINS_AWARDED, 0 );

	uint8 nGameModeId = getGameModeId();

	if ( nGameModeId == MODE_NORMAL )
	{
		// If we found any Troys...
		if ( nNumTroy)
		{
			// Three or more Troys will trigger the Troy Feature.
			if ( nNumTroy >= 3 )
			{
				// We have a winner.
				srFeatureTrigger = EVT_TROY_FEATURE;

				// Change the game mode.
				setGameModeId( MODE_TROY_FREE_SPIN );

				// Add the free spins.
				nFreeSpins = 10;
				incrementFreeSpins( nFreeSpins );
			}
			else
			{
				// Let the client know about it.
				srFeatureTrigger = EVT_TROY_FEATURE_NEAR_MISS;
			}

			// Add a scatter to the spin.
			spin->addScatter( nTroyScatter, 0, 0, false, srFeatureTrigger, nFreeSpins );
		}

		// If we found any Achilles...
		if ( nNumAchilles )
		{
			// This may have been set for the Troy feature.
			nFreeSpins = 0;

			// Three or more Achilles will trigger the Achilles feature.
			if ( nNumAchilles >= 3 )
			{
				// We have a winner.
				srFeatureTrigger = EVT_ACHILLES_FEATURE;

				// Change the game mode.
				setGameModeId( MODE_ACHILLES_FREE_SPIN );

				// Indicate that we are waiting on the player to select an Achilles icon.
				setSelectAchillesIcon( true );
				setAchillesIconMask( nAchillesScatter );

				// bwardlow 26-Jun-2006 #13332
				// The game can't complete until the bonus game is done.
				setGameCanComplete( false );

				// bwardlow 3-Jul-2006 #13362
				// get the number of free spins to award now so that we can put it in the scatter
				nFreeSpins = getRandomValueFromProbabilityTable( PT_NUM_ACHILLES_FREE_SPINS );
			}
			else
			{
				// Let the client know about it.
				srFeatureTrigger = EVT_ACHILLES_FEATURE_NEAR_MISS;
			}

			// Add a scatter to the spin.
			spin->addScatter( nAchillesScatter, 0, 0, false, srFeatureTrigger, nFreeSpins );
		}
	}
	else if ( nGameModeId == MODE_ACHILLES_FREE_SPIN )
	{
		// Note that there are no Troy icons during the Achilles feature game so we don't
		// have to worry about them here.

		// If we found any Achilles...
		if ( nNumAchilles )
		{
		    // Three or more Achilles will retrigger the Achilles feature.
		    if ( nNumAchilles >= 3 )
		    {
		    	// We have a winner.
		    	srFeatureTrigger = EVT_ACHILLES_FEATURE;

				// bwardlow 29-Jun-2006 #13356
				if ( !getMaxPayoutAwarded() )
				{
					// Indicate that we are waiting on the player to select an Achilles icon.
					setSelectAchillesIcon( true );
					setAchillesIconMask( nAchillesScatter );

					// bwardlow 26-Jun-2006 #13332
					// The game can't complete until the bonus game is done.
					setGameCanComplete( false );

					// bwardlow 3-Jul-2006 #13362
					// get the number of free spins to award now so that we can put it in the scatter
					nFreeSpins = getRandomValueFromProbabilityTable( PT_NUM_ACHILLES_FREE_SPINS );
				}
			}
			else
			{
				// Let the client know about it.
				srFeatureTrigger = EVT_ACHILLES_FEATURE_NEAR_MISS;
			}

			// Add a scatter to the spin.
			spin->addScatter( nAchillesScatter, 0, 0, false, srFeatureTrigger, nFreeSpins );
		}
	}
	else if ( nGameModeId == MODE_TROY_FREE_SPIN )
	{
		// Troy and Achilles act the same here.
		uint8 nNum = nNumAchilles + nNumTroy;
		int32 nScatter = nAchillesScatter | nTroyScatter;

		// If we found any of either...
		if ( nNum )
		{
			// Three or more icons will retrigger the Troy feature.
			if ( nNum >= 3 )
			{
				// We have a winner.
				srFeatureTrigger = EVT_TROY_FEATURE;

				// Add the free spins.
				nFreeSpins = 10;
				incrementFreeSpins( nFreeSpins );
			}
			else
			{
				// Let the client know about it.
				srFeatureTrigger = EVT_TROY_FEATURE_NEAR_MISS;
			}

			// Add a scatter to the spin.
			spin->addScatter( nScatter, 0, 0, false, srFeatureTrigger, nFreeSpins );
		}
	}
	else
	{
		ASSERT(!"Unknown Game Mode ID");
	}
}


////////////////////////////////////////////////////////////////////////////
/// @fn 	 AchillesGuts::processClientData( uint8 bonusGameType, int32 bonusDataCount, int32 *bonusData )
///
/// @param   bonusGameType      The current type of bonus game.
/// @param   bonusDataCount     The number of integers passed from the client.
/// @param   bonusData			An array of integers passed from the client.
///
/// This is an override of the framework method.
///
////////////////////////////////////////////////////////////////////////////
bool8 AchillesGuts::processClientData( uint8 bonusGameType, int32 bonusDataCount, int32 *bonusData )
{
	// Start by assuming that we do not need to reply to this message
	bool8 bReply = false;

	// Make sure it is appropriate to handle the bonus message (in case someone is trying to hack us).
	// bwardlow 17-Aug-2006 #14718 game mode gets reset to MODE_NORMAL on the last spin of the Achilles
	// feature even though the player is due more free spins because we are not storing the number
	// of free spins awarded in an orthodox manner -- just ignore the game mode and check the flag
	// in the subgame data
	if ( getSelectAchillesIcon() )
	{
		// Okay, we will be modifying subgame data, so a reply is needed.
		bReply = true;

		// bwardlow 3-Jul-2006 #13362
		// Retrieve the number of free spins awarded from the scatter.
		uint8 i, numScatters;
		SlotSpin* pSpin = getSlotSpin();
		SlotScatter* pScatter;
		int32 nFreeSpins = 0;

		numScatters = pSpin->getNumScatters();

		for ( i = 0; i < numScatters; i++ )
		{
			pScatter = pSpin->getScatter( i );
			if ( pScatter->payouttypeid == EVT_ACHILLES_FEATURE )
			{
				nFreeSpins = pScatter->freespins;
				break;
			}
		}

		// Add the free spins
		incrementFreeSpins( nFreeSpins );
		m_subGame->update( SGDIDX_FREE_SPINS_AWARDED, nFreeSpins );

		// Reset the Achilles selection flag.
		setSelectAchillesIcon( false );
		setAchillesIconMask( 0 );
	}

	// bwardlow 26-Jun-2006 #13332
	// The game can complete now that the bonus game is done.
	setGameCanComplete( true );

	return bReply;
}


////////////////////////////////////////////////////////////////////////////
/// @fn 	 AchillesGuts::getNumFeatureTriggerIcons( SlotSpin* spin, uint8 icon, int32& scatterPositions )
///
/// @param   spin				The current spin object.
/// @param   icon				The icon to search for.
/// @param   scatterPositions	The bit mask for the scatter positions that we find.
///
/// @return	 SpinResult			A payout from the SpinResult enumeration.
///
/// This helper method is used to evaluate the spin for scatters.
////////////////////////////////////////////////////////////////////////////
uint8  AchillesGuts::getNumFeatureTriggerIcons( SlotSpin* spin, uint8 icon, int32& scatterPositions ) const
{
	// Declare a local variable to keep up with the icon count.
	uint8 numFeatureTriggerIcons = 0;

	// Initialize the scatterPositions.
	scatterPositions = 0;

	// Loop through each reel.
  	for( uint8 reel = 0; reel < getReelCount(); reel++ )
	{
		// The position bit for the current icon in case it needs to be stored in a mask.
		uint8 position = reel;

		// Loop through each row in the wheel house.
		for( uint8 row = 0; row < 3; row++ )
		{
			// Get the current stop.
			uint8 stop = relativeWheelPosition( getGameModeId(), reel,
					spin->getStops()[ reel ], row );

			// Get the icon for the current stop.
			uint8 currentIcon = getIcon( getGameModeId(), reel, stop )->iconid;

			// If the icon is the one we are looking for...
			if ( currentIcon == icon )
			{
				// then increase the icon count
				numFeatureTriggerIcons++;

				// and set the bit in the position mask for this stop.
				scatterPositions |= 1 << position;
			}

			// Move to the next bit in the position mask.
   			position += 5;
		}
	}

	return numFeatureTriggerIcons;
}


////////////////////////////////////////////////////////////////////////////
/// @fn		AchillesGuts::tryForJackpot( SlotSpin* spin )
///
///	This function tries to win the jackpot and adds the scatter if we hit
/// the jackpot.
////////////////////////////////////////////////////////////////////////////
void AchillesGuts::tryForJackpot( SlotSpin* spin )
{
	// If we are in the first paid spin (NOT a bonus spin)...
	if ( getGameModeId() == MODE_NORMAL )
	{
		// then try for the Random Progressive Jackpot
		// If we hit the jackpot...
		if ( getRandomProgressiveJackpotResult( spin->getSpinLineCount() )
             || m_bForceRandomJackpot == true )
		{
			// then add a jackpot scatter to the spin.
			spin->addScatter( 0, getPayout( EVT_RANDOM_PROGRESSIVE_WINNER )->payoutAmount, 1,
				true, EVT_RANDOM_PROGRESSIVE_WINNER, 0 );
		}
    }
}


////////////////////////////////////////////////////////////////////////////
/// @fn 	 AchillesGuts::isValidGuts()
///
/// @return	 bool8      True if gut is valid.
///
/// This helper method is used to see if the current gut ID is valid.
////////////////////////////////////////////////////////////////////////////
bool8 AchillesGuts::isValidGuts()
{
	return getGutsId() >= MIN && getGutsId() < MAX ;
}


////////////////////////////////////////////////////////////////////////////
/// @fn 	 AchillesGuts::hasSavedGames()
///
/// This helper method is a framework override that indicates this machine can have saved games.
////////////////////////////////////////////////////////////////////////////
bool8 AchillesGuts::hasSavedGames()
{
	return true;
}


////////////////////////////////////////////////////////////////////////////
/// @fn 	 AchillesGuts::getGameModeMultiplierAndNoteId( uint8& nGameModeMultiplier, uint8& nNoteId )
///
/// @param   nGameModeMultiplier	The multiplier for the game mode.
/// @param   nNoteId				The note ID for the game mode.
///
/// This helper method is used to get the game mode multiplier and note ID.
////////////////////////////////////////////////////////////////////////////
void AchillesGuts::getGameModeMultiplierAndNoteId( uint8& nGameModeMultiplier,
	uint8& nNoteId )
{
	// If we are in Achilles Feature free spin mode...
    if ( getGameModeId() == MODE_ACHILLES_FREE_SPIN )
    {
		// then return the free spin multiplier...
        nGameModeMultiplier = MULTIPLIER_ACHILLES_FREE_SPIN;

		// and the free spin note.
        nNoteId = NOTE_ACHILLES_FREE_SPIN;
    }
	// Otherwise, if we are in Troy Feature free spin mode...
    else if ( getGameModeId() == MODE_TROY_FREE_SPIN )
    {
		// then return the free spin multiplier...
        nGameModeMultiplier = MULTIPLIER_TROY_FREE_SPIN;

		// and the free spin note.
        nNoteId = NOTE_TROY_FREE_SPIN;
    }
	// Otherwise...
    else
    {
		// just defer to the base class.
        SlotGuts::getGameModeMultiplierAndNoteId( nGameModeMultiplier, nNoteId );
    }
}

////////////////////////////////////////////////////////////////////////////
/// @fn 	 AchillesGuts::Debug_SetLoserStops( uint8* pStops )
///
/// @param   pStops		The stops to set.
///
/// Base class override, returns a losing spin triggered by the debug tool
////////////////////////////////////////////////////////////////////////////
void AchillesGuts::Debug_SetLoserStops( uint8* pStops )
{
	pStops[0]=0;
	pStops[1]=3;
	pStops[2]=0;
	pStops[3]=0;
	pStops[4]=0;
}

// bwardlow 17-Aug-2006 #14718 game mode gets reset to MODE_NORMAL on the last
// spin of the Achilles feature
////////////////////////////////////////////////////////////////////////////
/// @fn 	 AchillesGuts::postSpinClassifyResults( SlotSpin* spin )
///
/// @param   spin       Pointer to the spin with stop data.
///
/// This method is overridden to change the game mode if necessary.
////////////////////////////////////////////////////////////////////////////
void AchillesGuts::postSpinClassifyResults( SlotSpin* spin )
{
	// If we are waiting for the player to select an Achilles...
	if ( getSelectAchillesIcon() )
	{
		// then make sure we are in free spin mode
		setGameModeId( MODE_ACHILLES_FREE_SPIN );
	}
}


#ifdef DEBUG_KNOWNSPINS
////////////////////////////////////////////////////////////////////////////
/// @fn 	 AchillesGuts::preSpinClassifyResults( SlotSpin* spin )
///
/// @param   spin       Pointer to the spin with stop data.
///
/// This method is overridden in DEBUG_KNOWNSPINS to alter the reel stops.
////////////////////////////////////////////////////////////////////////////
void AchillesGuts::preSpinClassifyResults( SlotSpin* spin )
{
	#ifdef DEBUG_KNOWNSPINS
		// Handle any debug stops first.
		processDebugStops( spin );
	#endif
}


////////////////////////////////////////////////////////////////////////////
// The current spin number within the current data set.
////////////////////////////////////////////////////////////////////////////
int AchillesGuts::g_nSpinNum = 0;


////////////////////////////////////////////////////////////////////////////
// This array of stops should produce the payout result as denoted to the right of each entry.
// The array is indexed by the SpinResult, so g_aDebugStops[ EVT_FIVE_DANE ] will give you the
// set of stops that you need to land on a 5 Dane pay out on pay line 1.
////////////////////////////////////////////////////////////////////////////
uint8 AchillesGuts::g_aDebugStops[][5] =
{
	{    0,   9,   0,   0,   0 },	// EVT_LOSER,
	{    0,   5,   0,  14,  18 },	// EVT_SCATTER_NEAR_MISS,
	{    0,   7,   0,   5,   0 }, 	// EVT_FEATURE_NEAR_MISS,
	{    3,   5,   0,   0,   0 }, 	// EVT_ONE_ACHILLES,
	{    0,   1,   6,   0,   0 }, 	// EVT_TWO_HELM,
	{   14,   3,   0,   0,   0 }, 	// EVT_TWO_SHIELD,
	{    8,  22,   0,   0,   0 }, 	// EVT_TWO_HORSE,
	{   12,  16,   4,   1,   0 }, 	// EVT_THREE_TROY,
	{   17,  28,   0,   0,   0 }, 	// EVT_TWO_HELEN,
	{    6,   4,  19,  11,   0 }, 	// EVT_THREE_NINE,
	{   16,  21,   0,   7,  12 }, 	// EVT_THREE_TEN,
	{   18,   0,   3,   0,   0 }, 	// EVT_THREE_JACK,
	{    7,   2,   2,  11,   0 }, 	// EVT_THREE_QUEEN,
	{   19,   5,  12,   0,   0 }, 	// EVT_THREE_KING,
	{    5,   9,   7,   0,   0 }, 	// EVT_THREE_ACE,
	{    3,   7,   7,   0,   0 }, 	// EVT_TWO_ACHILLES,
	{    6,   4,  19,   1,   0 }, 	// EVT_FOUR_NINE,
	{   16,  21,   0,   4,  12 }, 	// EVT_FOUR_TEN,
	{    0,   1,   1,   0,   0 }, 	// EVT_THREE_HELM,
	{   14,   3,  14,   0,   0 }, 	// EVT_THREE_SHIELD,
	{   18,   0,   3,   3,   7 }, 	// EVT_FOUR_JACK,
	{    7,   2,   2,   0,   0 }, 	// EVT_FOUR_QUEEN,
	{   12,  16,   4,  14,   0 }, 	// EVT_FOUR_TROY,
	{   19,   5,  12,  10,  12 }, 	// EVT_FOUR_KING,
	{    5,   9,   7,   7,   0 }, 	// EVT_FOUR_ACE,
	{    8,  22,  28,   0,   0 }, 	// EVT_THREE_HORSE,
	{   17,  28,  18,   0,   0 }, 	// EVT_THREE_HELEN,
	{    0,   1,   1,   2,   0 }, 	// EVT_FOUR_HELM,
	{   14,   3,  14,   9,   0 }, 	// EVT_FOUR_SHIELD,
	{    6,   4,  19,   1,   4 }, 	// EVT_FIVE_NINE,
	{   16,  21,   0,   4,   6 }, 	// EVT_FIVE_TEN,
	{   18,   0,   3,   3,   1 }, 	// EVT_FIVE_JACK,
	{    7,   2,   2,   0,   3 }, 	// EVT_FIVE_QUEEN,
	{   19,   5,  12,  10,   0 }, 	// EVT_FIVE_KING,
	{    5,   9,   7,   7,  11 }, 	// EVT_FIVE_ACE,
	{    3,   7,  10,   0,   0 }, 	// EVT_THREE_ACHILLES,
	{    8,  22,  28,  44,   0 }, 	// EVT_FOUR_HORSE,
	{   12,  16,   4,  14,  18 }, 	// EVT_FIVE_TROY,
	{    0,   1,   1,   2,   5 }, 	// EVT_FIVE_HELM,
	{   14,   3,  14,   9,   2 }, 	// EVT_FIVE_SHIELD,
	{   17,  28,  18,  36,   0 }, 	// EVT_FOUR_HELEN,
	{    8,  22,  28,  44,  14 }, 	// EVT_FIVE_HORSE,
	{    3,   7,  10,   5,   0 }, 	// EVT_FOUR_ACHILLES,
	{   17,  28,  18,  36,  26 }, 	// EVT_FIVE_HELEN,
	{    3,   7,  10,   5,   9 }, 	// EVT_FIVE_ACHILLES,
};

uint8 AchillesGuts::g_aCustomDebugStops[][5] =
{
	{   21,   7,   0,   0,   0 },  // EVT_DEBUG_GAME_IDENTIFY
	{   14,  20,  43,  20,  80 },  // EVT_DEBUG_FREE_MODE_CHANGES
	{    0,   9,   5,  14,  17 },  // EVT_THREE_TROY_SCATTER
	{    0,  16,   3,  27,  17 },  // EVT_FOUR_TROY_SCATTER
	{   11,  17,   3,  27,  17 },  // EVT_FIVE_TROY_SCATTER
	{    0,   9,  11,   5,   8 },  // EVT_THREE_ACHILLES_SCATTER,
	{    0,   7,   9,   6,   8 },  // EVT_FOUR_ACHILLES_SCATTER,
	{    2,   8,   9,   6,   8 },  // EVT_FIVE_ACHILLES_SCATTER,
	{	12,  10,  27,  24,  63 },  // EVT_TROY_TO_ACHILLES,
	{	 6,  16,  27,  24,  63 },  // EVT_TROY_TO_HELEN_1,
	{	 6,  10,   4,  24,  63 },  // EVT_TROY_TO_HELEN_2,
	{	 6,  10,  27,  14,  63 },  // EVT_TROY_TO_HELEN_3,
	{	 6,  10,  27,  26,  63 },  // EVT_TROY_TO_HELEN_4,
	{	 6,  10,  27,  24,  18 },  // EVT_TROY_TO_HELEN_5,
	{	 8,  10,  27,  24,  63 },  // EVT_HORSE_TO_ACHILLES,

	{    4,  17,   0,   0,   0 },  // EVT_CUSTOM_STOP_1
	{    6,  17,  19,   1,   8 },  // EVT_CUSTOM_STOP_2 - one Achilles, one Troy
	{    6,  17,  11,   1,   8 },  // EVT_CUSTOM_STOP_3 - two Achilles, one Troy
	{    6,  17,   4,   1,   8 },  // EVT_CUSTOM_STOP_4 - one Achilles, two Troy
};

bool AchillesGuts::m_bForceRandomJackpot = false;


////////////////////////////////////////////////////////////////////////////
// Debug Stops Data Set 1
////////////////////////////////////////////////////////////////////////////
AchillesGuts::SpinResult AchillesGuts::g_aDataSet1[] =
{
	EVT_LOSER,
/*
	EVT_THREE_NINE,
	EVT_FOUR_NINE,
	EVT_FIVE_NINE,
	EVT_THREE_TEN,
	EVT_FOUR_TEN,
	EVT_FIVE_TEN,
	EVT_THREE_JACK,
	EVT_FOUR_JACK,
	EVT_FIVE_JACK,
	EVT_THREE_QUEEN,
	EVT_FOUR_QUEEN,
	EVT_FIVE_QUEEN,
	EVT_THREE_KING,
	EVT_FOUR_KING,
	EVT_FIVE_KING,
	EVT_THREE_ACE,
	EVT_FOUR_ACE,
	EVT_FIVE_ACE,
	EVT_TWO_HELM,
	EVT_THREE_HELM,
	EVT_FOUR_HELM,
	EVT_FIVE_HELM,
	EVT_TWO_SHIELD,
	EVT_THREE_SHIELD,
	EVT_FOUR_SHIELD,
	EVT_FIVE_SHIELD,
	EVT_TWO_HORSE,
	EVT_THREE_HORSE,
	EVT_FOUR_HORSE,
	EVT_FIVE_HORSE,
	EVT_TWO_HELEN,
	EVT_THREE_HELEN,
	EVT_FOUR_HELEN,
	EVT_FIVE_HELEN,
	EVT_THREE_TROY,
	EVT_THREE_TROY_SCATTER,
	EVT_FOUR_TROY,
	EVT_FOUR_TROY_SCATTER,
	EVT_FIVE_TROY,
	EVT_FIVE_TROY_SCATTER,
	EVT_DEBUG_FUNCTION_SUB_ACHILLES_1,
	EVT_LOSER,
	EVT_DEBUG_FUNCTION_SUB_ACHILLES_2,
	EVT_LOSER,
	EVT_DEBUG_FUNCTION_SUB_ACHILLES_3,
	EVT_LOSER,
	EVT_DEBUG_FUNCTION_SUB_ACHILLES_4,
	EVT_LOSER,
	EVT_DEBUG_FUNCTION_SUB_ACHILLES_5,
	EVT_LOSER,
	EVT_DEBUG_FUNCTION_SUB_TROY_1,
	EVT_LOSER,
	EVT_DEBUG_FUNCTION_SUB_TROY_2,
	EVT_LOSER,
	EVT_DEBUG_FUNCTION_SUB_TROY_3,
	EVT_LOSER,
	EVT_DEBUG_FUNCTION_SUB_TROY_4,
	EVT_LOSER,
	EVT_DEBUG_FUNCTION_SUB_TROY_5,
	EVT_LOSER,
	EVT_CUSTOM_STOP_1,
	EVT_CUSTOM_STOP_2,
	EVT_CUSTOM_STOP_3,
	EVT_CUSTOM_STOP_4,
	EVT_TROY_TO_ACHILLES,	// during Achilles feature
	EVT_TROY_TO_HELEN_1,	// during Achilles feature
	EVT_TROY_TO_HELEN_2,	// during Achilles feature
	EVT_TROY_TO_HELEN_3,	// during Achilles feature
	EVT_TROY_TO_HELEN_4,	// during Achilles feature
	EVT_TROY_TO_HELEN_5,	// during Achilles feature
	EVT_CUSTOM_STOP_1,
	EVT_THREE_ACHILLES_SCATTER,
	EVT_TROY_TO_ACHILLES,	// during Achilles feature
	EVT_TROY_TO_HELEN_1,	// during Achilles feature
	EVT_TROY_TO_HELEN_2,	// during Achilles feature
	EVT_TROY_TO_HELEN_3,	// during Achilles feature
	EVT_TROY_TO_HELEN_4,	// during Achilles feature
	EVT_TROY_TO_HELEN_5,	// during Achilles feature
	EVT_CUSTOM_STOP_1,
	EVT_THREE_ACHILLES_SCATTER,
	EVT_DEBUG_FUNCTION_FEATURE_EXIT,
*/	EVT_HORSE_TO_ACHILLES,	// during Troy feature
	EVT_THREE_TROY_SCATTER,
	EVT_HORSE_TO_ACHILLES,	// during Troy feature
	EVT_LOSER,
	EVT_LOSER,
	EVT_LOSER,
	EVT_LOSER,
	EVT_LOSER,
	EVT_LOSER,
	EVT_LOSER,
	EVT_LOSER,
	EVT_THREE_ACHILLES_SCATTER,
	EVT_LOSER,
	EVT_THREE_TROY_SCATTER,
	EVT_LOSER,
	EVT_CUSTOM_STOP_2,
	EVT_LOSER,
	EVT_CUSTOM_STOP_3,
	EVT_LOSER,
	EVT_CUSTOM_STOP_4,
	EVT_DEBUG_FUNCTION_FEATURE_EXIT,
/*	EVT_THREE_NINE,
	EVT_DEBUG_FUNCTION_FEATURE_EXIT,
	EVT_THREE_ACHILLES_SCATTER,
	EVT_THREE_NINE,
	EVT_DEBUG_FUNCTION_FEATURE_EXIT,
	EVT_FOUR_ACHILLES_SCATTER,
	EVT_FOUR_JACK,
	EVT_DEBUG_FUNCTION_FEATURE_EXIT,
	EVT_FIVE_ACHILLES_SCATTER,
	EVT_FOUR_KING,
	EVT_DEBUG_FUNCTION_FEATURE_EXIT,
*/
	EVT_DEBUG_DATA_SET_END
};


////////////////////////////////////////////////////////////////////////////
// Debug Stops Data Set 2
////////////////////////////////////////////////////////////////////////////
AchillesGuts::SpinResult AchillesGuts::g_aDataSet2[] =
{
//	EVT_DEBUG_FUNCTION_SUB_ACHILLES_1,
//	EVT_DEBUG_FUNCTION_SUB_ACHILLES_2,
//	EVT_LOSER,
//	EVT_DEBUG_FUNCTION_SUB_ACHILLES_1,
//	EVT_DEBUG_FUNCTION_SUB_ACHILLES_2,
//	EVT_LOSER,
//	EVT_DEBUG_FUNCTION_SUB_ACHILLES_2,
//	EVT_DEBUG_FUNCTION_SUB_ACHILLES_3,
//	EVT_LOSER,
//	EVT_DEBUG_FUNCTION_SUB_ACHILLES_3,
//	EVT_DEBUG_FUNCTION_SUB_ACHILLES_4,
//	EVT_LOSER,
//	EVT_DEBUG_FUNCTION_SUB_ACHILLES_4,
//	EVT_DEBUG_FUNCTION_SUB_ACHILLES_5,
//	EVT_LOSER,
//	EVT_THREE_ACHILLES_SCATTER,
//	EVT_DEBUG_FUNCTION_FEATURE_EXIT,
//	EVT_THREE_TROY_SCATTER,
//	EVT_THREE_TROY_SCATTER,
//	EVT_DEBUG_FUNCTION_FEATURE_EXIT,
	/*
	EVT_THREE_TROY_SCATTER,
	EVT_DEBUG_FUNCTION_SUB_ACHILLES_1,
	EVT_LOSER,
	EVT_DEBUG_FUNCTION_SUB_ACHILLES_2,
	EVT_LOSER,
	EVT_DEBUG_FUNCTION_SUB_ACHILLES_3,
	EVT_LOSER,
	EVT_DEBUG_FUNCTION_SUB_ACHILLES_4,
	EVT_LOSER,
	EVT_DEBUG_FUNCTION_SUB_ACHILLES_5,
	EVT_LOSER,
	EVT_DEBUG_FUNCTION_SUB_ACHILLES_1,
	EVT_DEBUG_FUNCTION_SUB_ACHILLES_2,
	EVT_LOSER,
	EVT_DEBUG_FUNCTION_SUB_ACHILLES_1,
	EVT_DEBUG_FUNCTION_SUB_ACHILLES_3,
	EVT_LOSER,
	EVT_DEBUG_FUNCTION_SUB_ACHILLES_1,
	EVT_DEBUG_FUNCTION_SUB_ACHILLES_4,
	EVT_LOSER,
	EVT_DEBUG_FUNCTION_SUB_ACHILLES_1,
	EVT_DEBUG_FUNCTION_SUB_ACHILLES_5,
	EVT_LOSER,
	EVT_DEBUG_FUNCTION_FEATURE_EXIT,
	EVT_FIVE_TROY_SCATTER,
	EVT_DEBUG_FUNCTION_SUB_TROY_1,
	EVT_DEBUG_FUNCTION_SUB_ACHILLES_2,
	EVT_LOSER,
	EVT_DEBUG_FUNCTION_SUB_ACHILLES_1,
	EVT_DEBUG_FUNCTION_SUB_TROY_2,
	EVT_LOSER,
	EVT_DEBUG_FUNCTION_SUB_TROY_2,
	EVT_DEBUG_FUNCTION_SUB_TROY_3,
	EVT_LOSER,
	EVT_DEBUG_FUNCTION_SUB_ACHILLES_2,
	EVT_DEBUG_FUNCTION_SUB_TROY_4,
	EVT_LOSER,
	EVT_DEBUG_FUNCTION_SUB_TROY_2,
	EVT_DEBUG_FUNCTION_SUB_ACHILLES_4,
	EVT_DEBUG_FUNCTION_SUB_TROY_5,
	EVT_LOSER,
	EVT_DEBUG_FUNCTION_SUB_TROY_2,
	EVT_DEBUG_FUNCTION_SUB_TROY_4,
	EVT_DEBUG_FUNCTION_SUB_TROY_5,
	EVT_LOSER,
	EVT_DEBUG_FUNCTION_SUB_ACHILLES_2,
	EVT_DEBUG_FUNCTION_SUB_ACHILLES_4,
	EVT_DEBUG_FUNCTION_SUB_ACHILLES_5,
	EVT_LOSER,
	EVT_DEBUG_FUNCTION_FEATURE_EXIT,
	*/
	//EVT_CUSTOM_STOP_1,

	EVT_THREE_TROY_SCATTER,
	EVT_DEBUG_FUNCTION_FEATURE_EXIT,
	EVT_THREE_ACHILLES_SCATTER,
	EVT_DEBUG_FUNCTION_FEATURE_EXIT,
	EVT_DEBUG_DATA_SET_END
};


////////////////////////////////////////////////////////////////////////////
// Debug Stops Data Set 3
////////////////////////////////////////////////////////////////////////////
AchillesGuts::SpinResult AchillesGuts::g_aDataSet3[] =
{
	EVT_LOSER,
	EVT_DEBUG_DATA_SET_END
};


////////////////////////////////////////////////////////////////////////////
// Debug Stops Data Set 4
////////////////////////////////////////////////////////////////////////////
AchillesGuts::SpinResult AchillesGuts::g_aDataSet4[] =
{
	EVT_LOSER,
	EVT_DEBUG_DATA_SET_END
};


////////////////////////////////////////////////////////////////////////////
// Debug Stops Data Set 5
////////////////////////////////////////////////////////////////////////////
AchillesGuts::SpinResult AchillesGuts::g_aDataSet5[] =
{
	EVT_LOSER,
	EVT_DEBUG_DATA_SET_END
};


////////////////////////////////////////////////////////////////////////////
// An array with pointers to all of the data sets.
////////////////////////////////////////////////////////////////////////////
AchillesGuts::SpinResult* AchillesGuts::g_aAllDataSets[] =
{
	g_aDataSet1,
	g_aDataSet2,
	g_aDataSet3,
	g_aDataSet4,
	g_aDataSet5
};


////////////////////////////////////////////////////////////////////////////
// The current data set that we are using.  This is a 1 based index into
// g_aAllDataSets, so 10 will cause the code to use g_aDataSet10.
////////////////////////////////////////////////////////////////////////////
int AchillesGuts::g_nCurrentDataSet = 2;


////////////////////////////////////////////////////////////////////////////
/// @fn		AchillesGuts::CopyDebugStops( SpinResult sr, uint8* pStops )
///
/// @param	sr		The spin result that we want to stop on.
/// @param	pStops	The stops to copy to.
///
/// This helper function copies the requested stops indicated by the spin
/// result to the pStops output parameter.
////////////////////////////////////////////////////////////////////////////
void AchillesGuts::CopyDebugStops( SpinResult sr, uint8* pStops )
{
	// If we are in the custom range...
	if ( sr >= EVT_DEBUG_CUSTOM_STOPS )
	{
		// then make sure that we are within the bounds of the custom array.
		ASSERT( sr - EVT_DEBUG_CUSTOM_STOPS < countof( g_aCustomDebugStops ) );

		// Copy each stop from the custom array.
		pStops[0] = g_aCustomDebugStops[ sr - EVT_DEBUG_CUSTOM_STOPS ][0];
		pStops[1] = g_aCustomDebugStops[ sr - EVT_DEBUG_CUSTOM_STOPS ][1];
		pStops[2] = g_aCustomDebugStops[ sr - EVT_DEBUG_CUSTOM_STOPS ][2];
		pStops[3] = g_aCustomDebugStops[ sr - EVT_DEBUG_CUSTOM_STOPS ][3];
		pStops[4] = g_aCustomDebugStops[ sr - EVT_DEBUG_CUSTOM_STOPS ][4];
	}
	else
	{
		// Otherwise make sure we are within the bounds of the normal array.
		ASSERT( sr < countof( g_aDebugStops ) );

		// Copy each stop from the normal array.
		pStops[0] = g_aDebugStops[ sr ][0];
		pStops[1] = g_aDebugStops[ sr ][1];
		pStops[2] = g_aDebugStops[ sr ][2];
		pStops[3] = g_aDebugStops[ sr ][3];
		pStops[4] = g_aDebugStops[ sr ][4];
	}
}


////////////////////////////////////////////////////////////////////////////
/// @fn 	 AchillesGuts::DebugStops_ReelConfig( uint8* pStops )
///
/// @param   pStops		The stops to set.
///
/// This custom debug stop function will iterate through each stop on the
/// reels.
////////////////////////////////////////////////////////////////////////////
void AchillesGuts::DebugStops_ReelConfig( uint8* pStops )
{
	// Make these static so they don't go away between function calls.
	static int8 g_nReel = -1;
	static uint8 g_nStop = 0;

	// Store our global variables in local copies so that we can see them easily
	// in the debugger.
	int8 nReel = g_nReel;
	uint8 nStop = g_nStop;

	// If this is the first spin...
	if ( nReel == -1 )
	{
		// then stop at a position where the player can see
		// whether we are on the 97.5% gut or the 95% gut.
		CopyDebugStops( EVT_DEBUG_GAME_IDENTIFY, pStops );

		// Now move on to reel 0.
		nReel = 0;
	}
	else
	{
		// Zero everything out initially.
		pStops[ 0 ] = 0;
		pStops[ 1 ] = 0;
		pStops[ 2 ] = 0;
		pStops[ 3 ] = 0;
		pStops[ 4 ] = 0;

		// Set the current stop on the current reel.
		pStops[ nReel ] = nStop;

		// Increment the stop in preparation for the next call.
		nStop++;

		// See if we are at the end of this reel.
		if ( nStop == getIconCount( getGameModeId(), nReel ) )
		{
			// Wrap around to the beginning of the next reel.
			nStop = 0;

			// Move to the next reel.
			nReel++;

			// See if we are finished with the last reel and need to wrap
			// back around to the beginning of the sequence.
			if ( nReel == 5 )
			{
				// Set the reel back to its initial value of -1, which will
				// cause the next call to stop at the EVT_DEBUG_GAME_IDENTIFY
				// stops.
				nReel = -1;
			}
		}
	}

	// Finally, store our local variables back in the globals for persistence.
	g_nReel = nReel;
	g_nStop = nStop;
}


////////////////////////////////////////////////////////////////////////////
/// @fn 	 AchillesGuts::DebugStops_FeatureExitWin( uint8* pStops )
///
/// @param   pStops		The stops to set.
///
/// This custom debug stop function will return winning spins until the free
/// game feature is over.
////////////////////////////////////////////////////////////////////////////
void AchillesGuts::DebugStops_FeatureExitWin( uint8* pStops )
{
	// Return a losing spin.
	CopyDebugStops( EVT_LOSER, pStops );

	// If there are still more free spins remaining...
	if ( getFreeSpins() > 1 )
	{
		// then decrement the global spin number, which will cause this
		// function to be called again.
		g_nSpinNum--;
	}
}


////////////////////////////////////////////////////////////////////////////
/// @fn 	 AchillesGuts::DebugStops_FeatureExit( uint8* pStops )
///
/// @param   pStops		The stops to set.
///
/// This custom debug stop function will return losing spins until the free
/// game feature is over.
////////////////////////////////////////////////////////////////////////////
void AchillesGuts::DebugStops_FeatureExit( uint8* pStops )
{
	// Return a losing spin.
	CopyDebugStops( EVT_LOSER, pStops );

	// If there are still more free spins remaining...
	if ( getFreeSpins() > 1 )
	{
		// then decrement the global spin number, which will cause this
		// function to be called again.
		g_nSpinNum--;
	}
}


////////////////////////////////////////////////////////////////////////////
/// @fn 	 AchillesGuts::DebugStops_ScatterIterate( uint8* pStops )
///
/// @param   pStops		The stops to set.
///
/// This custom debug stop function will iterate through each possible
/// combination of scatter stops.
////////////////////////////////////////////////////////////////////////////
void AchillesGuts::DebugStops_ScatterIterate( uint8* pStops )
{
/*
	// Keep up with our own iteration number.
	static int g_nIteration = 0;

	// Store the global variable in a local copy so that we can manipulate
	// it in the debugger easily.
	int nIteration = g_nIteration;

	// Set the stops to five scatter icons to start with.
	CopyDebugStops( EVT_THREE_HILLBILLY, pStops );

	// Now adjust everything to the stop just after the scatter icons.
	// Adding 2 will move the scatter icon just above the top line in the
	// wheel house.
	pStops[ 0 ] += 2;
	pStops[ 1 ] += 2;
	pStops[ 2 ] += 2;
	pStops[ 3 ] += 2;
	pStops[ 4 ] += 2;

	// Now adjust each icon individually based on the current iteration number.
	// There are 4 possible positions for each icon: none, top row, middle row, bottom row.
	// Those posistions can be represented by 2 bits: 00, 01, 10, 11 -or- 0, 1, 2, 3 in decimal.
	// This just happens to be how much we need to subtact from the stop for each reel in order to
	// move the icon between the 4 different states.
	// Now, there are 5 reels, so we will need 5 sets of these 2 bits, or 10 bits.
	// That gives a total of 1024 combinations.  How can we iterate through each of the
	// possible permutations?  Easy... just count to 1024.  This will turn the bits on and off
	// in every possible combination.  Just use the current interation number as the set of bits
	// to adjust the reel stops with.  And when we get to 1024 it will magically wrap around
	// because we ignore everything above the 10 bits we are using.

	// OK here we go... adjust each reel stop by the correct set of bits in the iteration number.
//	pStops[ 0 ] -= ( nIteration & 0x0003 );			// the first two bits...  00 00 00 00 11.
//	pStops[ 1 ] -= ( nIteration & 0x000C ) >> 2;	// the second two bits... 00 00 00 11 00, shifted to the right so they are in the correct place to subtract from the stop.
//	pStops[ 2 ] -= ( nIteration & 0x0030 ) >> 4;	// the third two bits...  00 00 11 00 00
//	pStops[ 3 ] -= ( nIteration & 0x00c0 ) >> 6;	// the fourth two bits... 00 11 00 00 00
//	pStops[ 4 ] -= ( nIteration & 0x0300 ) >> 8;	// the fifth two bits...  11 00 00 00 00

	// In the Hillbillies case, since we have only three scatter icons, we can cover all
	// possibilities in just 64 iterations.
	pStops[ 0 ] -= ( nIteration & 0x0003 );			// the first two bits...  00 00 00 00 11.
	pStops[ 2 ] -= ( nIteration & 0x000C ) >> 2;	// the second two bits... 00 00 00 11 00, shifted to the right so they are in the correct place to subtract from the stop.
	pStops[ 4 ] -= ( nIteration & 0x0030 ) >> 4;	// the third two bits...  00 00 11 00 00


	// Now wasn't that simple?  The implementation that is.  The explanation is 100 times
	// more complicated. :)

	// Move to the next iteration.
	nIteration++;

	// Save the local back in the global for persistance.
	g_nIteration = nIteration;
*/
}


////////////////////////////////////////////////////////////////////////////
/// @fn 	 AchillesGuts::DebugStops_PayLineIterate( uint8* pStops )
///
/// @param   pStops		The stops to set.
///
/// This custom debug stop function will iterate through each possible
/// pay line, stopping on five 9's for each one.
////////////////////////////////////////////////////////////////////////////
void AchillesGuts::DebugStops_PayLineIterate( uint8* pStops )
{
	// Declare an array to look up the offset for a reel for each payline.
	// An offset of 0 means that the reel should stop on the middle row,
	// an offset of 1 means the reel should stop on the top row,
	// and an offset of -1 means the reel should stop on the bottom row.
	// So the offset is relative to the middle row, or pay line 1.
	// Note: these offsets where taken directly from the graphic at the
	// bottom of the first help screen.  That way we will be verifying
	// that the pay lines match the help screen instead of verifying
	// that the pay lines match the database.  If they match the help
	// screen, we have verified that both the database and the pay line
	// code is correct.
	static int8 g_nPayLineOffset[20][5] =
	{
		{  0,  0,  0,  0,  0 },	// Pay line 1
		{  1,  1,  1,  1,  1 },	// Pay line 2
		{ -1, -1, -1, -1, -1 },	// Pay line 3
		{  1,  0, -1,  0,  1 },	// Pay line 4
		{ -1,  0,  1,  0, -1 },	// Pay line 5
		{  0,  1,  0,  1,  0 },	// Pay line 6
		{  0, -1,  0, -1,  0 },	// Pay line 7
		{  1,  0,  1,  0,  1 },	// Pay line 8
		{ -1,  0, -1,  0, -1 },	// Pay line 9
		{  0,  1,  1,  1,  0 },	// Pay line 10
		{  0, -1, -1, -1,  0 },	// Pay line 11
		{ -1, -1,  0, -1, -1 },	// Pay line 12
		{  1,  1,  0,  1,  1 },	// Pay line 13
		{ -1,  0,  0,  0, -1 },	// Pay line 14
		{  1,  0,  0,  0,  1 },	// Pay line 15
		{  1, -1,  1, -1,  1 },	// Pay line 16
		{ -1,  1, -1,  1, -1 },	// Pay line 17
		{  0,  0,  1,  0,  0 },	// Pay line 18
		{  0,  0, -1,  0,  0 },	// Pay line 19
		{ -1, -1,  1, -1, -1 }	// Pay line 20
	};

	// Keep up with our own iteration number.
	static int g_nIteration = 0;

	// Store the global variable in a local copy so that we can manipulate
	// it in the debugger easily.
	int nIteration = g_nIteration;

	// Set the stops to five 9's to start with.
	CopyDebugStops( EVT_FIVE_NINE, pStops );

	// Now adjust everything to the current payline.
	pStops[ 0 ] += g_nPayLineOffset[ nIteration ][ 0 ];
	pStops[ 1 ] += g_nPayLineOffset[ nIteration ][ 1 ];
	pStops[ 2 ] += g_nPayLineOffset[ nIteration ][ 2 ];
	pStops[ 3 ] += g_nPayLineOffset[ nIteration ][ 3 ];
	pStops[ 4 ] += g_nPayLineOffset[ nIteration ][ 4 ];

	// Move to the next iteration.
	nIteration++;

	// See if we need to wrap back around.
	if ( nIteration == countof( g_nPayLineOffset ) )
	{
		// Wrap back around to 0.
		nIteration = 0;
	}

	// Save the local back in the global for persistance.
	g_nIteration = nIteration;
}


////////////////////////////////////////////////////////////////////////////
/// @fn 	 AchillesGuts::DebugStops_RandomJackpot( uint8* pStops )
///
/// @param   pStops		The stops to set.
///
/// This custom debug stop function will hit the progressive jackpot.
////////////////////////////////////////////////////////////////////////////
void AchillesGuts::DebugStops_RandomJackpot( uint8* pStops )
{
	// Initialize the stops.
	CopyDebugStops( EVT_LOSER, pStops );

	// Force the jackpot scatter
	m_bForceRandomJackpot = true;
}


////////////////////////////////////////////////////////////////////////////
/// @fn 	 AchillesGuts::DebugStops_RandomJackpotNext( uint8* pStops )
///
/// @param   pStops		The stops to set.
///
/// This custom debug stop function will hit the progressive jackpot.
////////////////////////////////////////////////////////////////////////////
void AchillesGuts::DebugStops_RandomJackpotNext( uint8* pStops )
{
	// Force the jackpot scatter
	m_bForceRandomJackpot = true;
}


////////////////////////////////////////////////////////////////////////////
/// @fn 	 AchillesGuts::DebugStops_SubstituteAchilles1( uint8* pStops )
///
/// @param   pStops		The stops to set.
///
/// This custom debug stop function will replace reel 1 with Achilles.
////////////////////////////////////////////////////////////////////////////
void AchillesGuts::DebugStops_SubstituteAchilles1( uint8* pStops )
{
	pStops[ 0 ] = DebugStops_findStopWithIconID( 0, ICON_ACHILLES, 1 );
}


////////////////////////////////////////////////////////////////////////////
/// @fn 	 AchillesGuts::DebugStops_SubstituteAchilles2( uint8* pStops )
///
/// @param   pStops		The stops to set.
///
/// This custom debug stop function will replace reel 2 with Achilles.
////////////////////////////////////////////////////////////////////////////
void AchillesGuts::DebugStops_SubstituteAchilles2( uint8* pStops )
{
	pStops[ 1 ] = DebugStops_findStopWithIconID( 1, ICON_ACHILLES, 1 );
}


////////////////////////////////////////////////////////////////////////////
/// @fn 	 AchillesGuts::DebugStops_SubstituteAchilles3( uint8* pStops )
///
/// @param   pStops		The stops to set.
///
/// This custom debug stop function will replace reel 3 with Achilles.
////////////////////////////////////////////////////////////////////////////
void AchillesGuts::DebugStops_SubstituteAchilles3( uint8* pStops )
{
	pStops[ 2 ] = DebugStops_findStopWithIconID( 2, ICON_ACHILLES, 1 );
}


////////////////////////////////////////////////////////////////////////////
/// @fn 	 AchillesGuts::DebugStops_SubstituteAchilles4( uint8* pStops )
///
/// @param   pStops		The stops to set.
///
/// This custom debug stop function will replace reel 4 with Achilles.
////////////////////////////////////////////////////////////////////////////
void AchillesGuts::DebugStops_SubstituteAchilles4( uint8* pStops )
{
	pStops[ 3 ] = DebugStops_findStopWithIconID( 3, ICON_ACHILLES, 1 );
}


////////////////////////////////////////////////////////////////////////////
/// @fn 	 AchillesGuts::DebugStops_SubstituteAchilles5( uint8* pStops )
///
/// @param   pStops		The stops to set.
///
/// This custom debug stop function will replace reel 5 with Achilles.
////////////////////////////////////////////////////////////////////////////
void AchillesGuts::DebugStops_SubstituteAchilles5( uint8* pStops )
{
	pStops[ 4 ] = DebugStops_findStopWithIconID( 4, ICON_ACHILLES, 1 );
}


////////////////////////////////////////////////////////////////////////////
/// @fn 	 AchillesGuts::DebugStops_SubstituteTroy1( uint8* pStops )
///
/// @param   pStops		The stops to set.
///
/// This custom debug stop function will replace reel 1 with Troy.
////////////////////////////////////////////////////////////////////////////
void AchillesGuts::DebugStops_SubstituteTroy1( uint8* pStops )
{
	pStops[ 0 ] = DebugStops_findStopWithIconID( 0, ICON_TROY, 1 );
}


////////////////////////////////////////////////////////////////////////////
/// @fn 	 AchillesGuts::DebugStops_SubstituteTroy2( uint8* pStops )
///
/// @param   pStops		The stops to set.
///
/// This custom debug stop function will replace reel 2 with Troy.
////////////////////////////////////////////////////////////////////////////
void AchillesGuts::DebugStops_SubstituteTroy2( uint8* pStops )
{
	pStops[ 1 ] = DebugStops_findStopWithIconID( 1, ICON_TROY, 1 );
}


////////////////////////////////////////////////////////////////////////////
/// @fn 	 AchillesGuts::DebugStops_SubstituteTroy3( uint8* pStops )
///
/// @param   pStops		The stops to set.
///
/// This custom debug stop function will replace reel 3 with Troy.
////////////////////////////////////////////////////////////////////////////
void AchillesGuts::DebugStops_SubstituteTroy3( uint8* pStops )
{
	pStops[ 2 ] = DebugStops_findStopWithIconID( 2, ICON_TROY, 1 );
}


////////////////////////////////////////////////////////////////////////////
/// @fn 	 AchillesGuts::DebugStops_SubstituteTroy4( uint8* pStops )
///
/// @param   pStops		The stops to set.
///
/// This custom debug stop function will replace reel 4 with Troy.
////////////////////////////////////////////////////////////////////////////
void AchillesGuts::DebugStops_SubstituteTroy4( uint8* pStops )
{
	pStops[ 3 ] = DebugStops_findStopWithIconID( 3, ICON_TROY, 1 );
}


////////////////////////////////////////////////////////////////////////////
/// @fn 	 AchillesGuts::DebugStops_SubstituteTroy5( uint8* pStops )
///
/// @param   pStops		The stops to set.
///
/// This custom debug stop function will replace reel 5 with Troy.
////////////////////////////////////////////////////////////////////////////
void AchillesGuts::DebugStops_SubstituteTroy5( uint8* pStops )
{
	pStops[ 4 ] = DebugStops_findStopWithIconID( 4, ICON_TROY, 1 );
}


////////////////////////////////////////////////////////////////////////////
// This array of function pointers is used to call custom functions to
// generate the debug stops.
////////////////////////////////////////////////////////////////////////////
AchillesGuts::DEBUG_STOP_PROC AchillesGuts::g_FunctionTable[] =
{
	&DebugStops_ReelConfig,
    &DebugStops_FeatureExit,
	&DebugStops_ScatterIterate,
	&DebugStops_PayLineIterate,
	&DebugStops_RandomJackpot,
	&DebugStops_FeatureExitWin,
    &DebugStops_RandomJackpotNext,
	&DebugStops_SubstituteAchilles1,
	&DebugStops_SubstituteAchilles2,
	&DebugStops_SubstituteAchilles3,
	&DebugStops_SubstituteAchilles4,
	&DebugStops_SubstituteAchilles5,
	&DebugStops_SubstituteTroy1,
	&DebugStops_SubstituteTroy2,
	&DebugStops_SubstituteTroy3,
	&DebugStops_SubstituteTroy4,
	&DebugStops_SubstituteTroy5,
};


////////////////////////////////////////////////////////////////////////////
/// @fn 	AchillesGuts::processDebugStops( SlotSpin* spin )
///
/// @param   spin       Pointer to the spin with stop data.
///
/// This helper method is used in DEBUG_KNOWNSPINS to alter the reel stops.
////////////////////////////////////////////////////////////////////////////
void AchillesGuts::processDebugStops( SlotSpin* spin )
{
    // If this ASSERT fires then you must have manually set g_nCurrentDataSet
	// to an invalid value or it was initialized to an invalid value.
	// Note: the data sets are 1 based so they will match the documentation!
	ASSERT( g_nCurrentDataSet >= 1 && g_nCurrentDataSet <= countof( g_aAllDataSets ) );

	// Get the current data set that we are using.
	SpinResult* aDataSet = g_aAllDataSets[ g_nCurrentDataSet - 1 ];

	// If we are at the end of the data set...
    if ( aDataSet[ g_nSpinNum ] == EVT_DEBUG_DATA_SET_END )
    {
		// then wrap around to the beginning.
        g_nSpinNum = 0;
    }

    // Get a pointer to the stops array and cast away the constness.
    uint8* pStops = const_cast<uint8*>( spin->getStops() );

    // Force this to false on every pass, to make sure we don't leave it hanging around as true.
    m_bForceRandomJackpot = false;

	// If we are supposed to use a function for this spin...
	if ( aDataSet[ g_nSpinNum ] >= EVT_DEBUG_CUSTOM_FUNCTIONS )
	{
		// then get the correct function from the function table.
		DEBUG_STOP_PROC pFunction = g_FunctionTable[ aDataSet[ g_nSpinNum ] - EVT_DEBUG_CUSTOM_FUNCTIONS ];

        // If this is a value that works on the result of the next spin, go ahead and
        // make that next spin, then apply the function to it's results.
		if (  aDataSet[ g_nSpinNum ] >= EVT_DEBUG_MODIFY_NEXT_SPIN_FUNCTIONS )
		{
			// Get the next spin before calling the function.
			g_nSpinNum++;
			processDebugStops( spin );
			--g_nSpinNum;
		}

		// Call the function.
		(this->*pFunction)( pStops );
	}
	else
	{
		// Otherwise copy the stops from one of our arrays.
		CopyDebugStops( aDataSet[ g_nSpinNum ], pStops );
	}

    // Go to the next stop.
	g_nSpinNum++;
}
#endif // DEBUG_KNOWNSPINS
